package com.mazaiting.web.auth.security.config;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.mazaiting.redis.service.IRedisService;
import com.mazaiting.redisson.service.IRedissonService;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Objects;

/**
 * ID_WORK 中工作 ID 与数据中心值动态修改
 *
 * @author mazaiting
 * @create_time 2022/8/27 11:38
 */
@Component
public class IdWorkConfig {

    /**
     * Mybatis ID Work 分布式锁前缀
     */
    public static final String LOCK_MY_BATIS_PREFIX = "mybatis:";
    /**
     * 工作 ID 键
     */
    public static final String KEY_WORKER_ID = "mybatis:worker:id";
    /**
     * 数据 ID 键
     */
    public static final String KEY_DATA_ID = "mybatis:data:id";
    private final Logger logger = LoggerFactory.getLogger(IdWorkConfig.class);

    @Resource
    private IRedisService redisService;
    @Resource
    private IRedissonService redissonService;

    /**
     * 更换默认的idWorker
     */
    @PostConstruct
    public void changeIdWorker() {
        RLock lock = null;
        try {
            // 获取锁
            lock = redissonService.getLock(LOCK_MY_BATIS_PREFIX + "id:worker");
            // 加锁
            lock.lock();
            // 工作 ID
            int workId = 0;
            // 数据 ID
            int dataId;
            while (true) {
                // redis中取值
                Object workIdObj = redisService.get(KEY_WORKER_ID);
                if (Objects.nonNull(workIdObj)) {
                    workId = (int) workIdObj;
                }
                //判断值
                dataId = Math.toIntExact(redisService.incr(KEY_DATA_ID, 1L));
                if (dataId > 31) {
                    // 设置数据 ID
                    redisService.set(KEY_DATA_ID, 0L);
                    // 自增工作 ID
                    workId = Math.toIntExact(redisService.incr(KEY_WORKER_ID, 1L));
                    if (workId > 31) {
                        redisService.set(KEY_WORKER_ID, 0L);
                    }
                    continue;
                }
                break;
            }
            logger.info("changeIdWorker workId:{},dataId:{}", workId, dataId);
            IdWorker.initSequence(workId, dataId);
        } catch (Exception e) {
            logger.error("初始化 workId 与 dataId 失败: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(lock)) {
                lock.unlock();
            }
        }
    }
}
